﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;
using Microsoft.Win32;

/**
 *
 * @author eladh, alaah
 */

namespace Windows_System_Snapshot
{
	abstract class LogicAbstract 
    {
    	//
    	
    	public static string lspciPath = "";
        // 
        public bool isDone = false;

        // DEFAULT_OUTPUT_PATH for the html file 
        public static string DEFAULT_OUTPUT_PATH = System.Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) 
            + "\\system_snapshot_" 
            + Environment.MachineName + "_"
            + Regex.Replace(Regex.Replace(Regex.Replace(DateTime.Now.ToString(), " ", "_"), ":", "-"), "/", "-")
            + ".html";

        // Number of columns for the index table
        private static int COLUMNS = 4;

        // The HTML ouput text
        StringBuilder html = new StringBuilder();

        // Linked lists to hold registry paths or cmd commnads for both server and fabric
        ArrayList serverInfoList = new ArrayList();
        ArrayList eventLogsList = new ArrayList();
        ArrayList mlxRegValues = new ArrayList();
        ArrayList fabricInfoList = new ArrayList();
        ArrayList smbInfoList = new ArrayList();
        ArrayList perfTestList = new ArrayList();
        ArrayList fileList = new ArrayList();

        // File handler
        StreamWriter outStream = null;

        private string HTMLpath = "";
        Thread myThread = null; // thread for the whole algorithm

        //Thread commandThread = null;// thread for running a single command

        // max seconds that we will wait for a command to return it's output.
        public static int timeOutSec = 15;

        private String proccessedCommand = "";
        
        // 
        // settings object for performance tests
        //
        public static ArrayList cards = null;
        public static PerformanceConf perfConfig = null;
        
        //
        private string rcbg_Cmd = "";
       	private string rcbg_Arg = "";
        
        //-------------------------------------------------------------------------------------------
        //
        /// <summary>
        /// constructor; builds the lists of commands that will be processed later.
        /// </summary>
        public LogicAbstract()
        {
            // set default output path
            HTMLpath = DEFAULT_OUTPUT_PATH;

            // --------
            // Insert Server information to a list
            serverInfoList.Add(new Command("Host name", "hostname", "", "CMD"));
            serverInfoList.Add(new Command("Windows Version", "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion","ProductName", "REG"));
            serverInfoList.Add(new Command("CPU Type", "HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\Environment", "PROCESSOR_IDENTIFIER", "REG"));
            serverInfoList.Add(new Command("CPU info", "HKEY_LOCAL_MACHINE\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", null, "REG"));
            serverInfoList.Add(new Command("CPU management", "wmic", "CPU list /format:list", "CMD"));
            serverInfoList.Add(new Command("System product information", "wmic", "CSPRODUCT list /format:list", "CMD"));
            serverInfoList.Add(new Command("BIOS settings", "wmic", "bios get /format:list", "CMD"));
            serverInfoList.Add(new Command("System Bios Date", "HKEY_LOCAL_MACHINE\\HARDWARE\\DESCRIPTION\\System", "SystemBiosDate", "REG"));
            serverInfoList.Add(new Command("Computer system management", "wmic", "COMPUTERSYSTEM list /format:list", "CMD"));
            serverInfoList.Add(new Command("Disk Free Space", "fsutil", "volume diskfree c:", "CMD"));
            serverInfoList.Add(new Command("System Info", "systeminfo", "", "CMD"));
            serverInfoList.Add(new Command("path", "cmd", "/c path", "CMD"));
            serverInfoList.Add(new Command("set U", "cmd", "/c set U", "CMD"));
            serverInfoList.Add(new Command("set L", "cmd", "/c set L", "CMD"));
            serverInfoList.Add(new Command("set", "cmd", "/c set", "CMD"));
            serverInfoList.Add(new Command("Running processes", "tasklist", "/fo csv /nh /V", "tasklist"));
            serverInfoList.Add(new Command("Installed Drivers", "DRIVERQUERY", "/V /FO CSV", "drivers"));
            serverInfoList.Add(new Command("gpresult /R", "gpresult", "/R", "CMD"));
            serverInfoList.Add(new Command("gpresult /Z", "gpresult", "/Z", "CMD"));
            serverInfoList.Add(new Command("lspci", "", "", "lspci"));
            serverInfoList.Add(new Command("lspci -tv", "", "-tv", "lspci"));

            // --------
            // mlxRegValues
            mlxRegValues.Add(new Command("Mellanox adapters list", "", "", "mlxNetAdpList"));   // pci info 
            mlxRegValues.Add(new Command("MST devices query", "", "", "queryViaMFT"));
            mlxRegValues.Add(new Command("Mellanox adapters Settings", "", "", "mlxNetAdpSettings"));
            mlxRegValues.Add(new Command("General Registry Values", "", "", "generalRegistryValues"));
            mlxRegValues.Add(new Command("MLX4_bus Parameters", "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\services\\mlx4_bus\\Parameters", null, "REG"));
            
            
            // --------
            // export event logs and add them to the HTML file.
            // - list of events to get
            String[] eventsList = { "IPSEC-SRV", "mlx4_bus", "mlx4_hca", "mlx4eth62", "NDIS", "NetBIOS", "NetBT", "Network Access Protection", "Network and Sharing Center", "NetworkGCW", "Networking-Correlation", "NetworkManagerTriggerProvider", "NetworkProfile", "PCI", "TCP/IP", "Tcpip", "TCPIP", "Tcpip6", "Tcpip-SQM-Provider", "TCPMon", "Application Error", "Windows Error Reporting" };

            // - build the query
            String eventsCMD = "@Name='" + eventsList[0] + "'";
            for (int i = 1; i < eventsList.Length; i++)
            {
                eventsCMD += " or @Name='" + eventsList[i] + "'";
            }
            eventsCMD += "]]]\" /f:text";
            // - System
            eventLogsList.Add(new Command("System Event Logs", "wevtutil", "qe System /q:\"*[System[Provider[" + eventsCMD, "CMD"));
            // - Application
            eventLogsList.Add(new Command("Application Event Logs", "wevtutil", "qe Application /q:\"*[System[Provider[" + eventsCMD, "CMD"));
            // - Setup
            eventLogsList.Add(new Command("Setup Event Logs", "wevtutil", "qe Setup /q:\"*[System[Provider[" + eventsCMD, "CMD"));
            //            
            
            // --------
            // Insert Fabric information to a list
            fabricInfoList.Add(new Command("sminfo", "sminfo", "", "CMD"));
            fabricInfoList.Add(new Command("vstat", "vstat", "", "CMD"));
            fabricInfoList.Add(new Command("vstat -v", "vstat", "-v", "CMD"));
            fabricInfoList.Add(new Command("vstat -m", "vstat", "-m", "CMD"));
            fabricInfoList.Add(new Command("vstat -c", "vstat", "-c", "CMD"));
            fabricInfoList.Add(new Command("ibstat", "ibstat", "", "CMD"));
            fabricInfoList.Add(new Command("ibv_devinfo", "ibv_devinfo", "", "CMD"));
            fabricInfoList.Add(new Command("ibv_devinfo -v", "ibv_devinfo", "-v", "CMD"));
            fabricInfoList.Add(new Command("ibaddr", "ibaddr", "", "CMD"));
            fabricInfoList.Add(new Command("ibaddr -e -v -d", "ibaddr", "-e -v -d", "CMD"));
            fabricInfoList.Add(new Command("iblinkinfo", "iblinkinfo", "", "CMD"));
            fabricInfoList.Add(new Command("saquery", "saquery", "", "CMD"));
            fabricInfoList.Add(new Command("saquery -e", "saquery", "-e", "CMD"));
            fabricInfoList.Add(new Command("saquery -s", "saquery", "-s", "CMD"));
            fabricInfoList.Add(new Command("saquery -S ", "saquery", "-S", "CMD"));
            fabricInfoList.Add(new Command("saquery -c", "saquery", "-c", "CMD"));
            fabricInfoList.Add(new Command("saquery -g", "saquery", "-g", "CMD"));
            fabricInfoList.Add(new Command("saquery -x", "saquery", "-x", "CMD"));
            fabricInfoList.Add(new Command("saquery -m", "saquery", "-m", "CMD"));
            fabricInfoList.Add(new Command("ibnetdiscover", "ibnetdiscover", "", "CMD"));
            fabricInfoList.Add(new Command("ibnetdiscover -gn", "ibnetdiscover", "-gn", "CMD"));
            fabricInfoList.Add(new Command("Firewall", "netsh", "advfirewall show allprofiles", "CMD"));
            fabricInfoList.Add(new Command("ipconfig /all", "ipconfig.exe", "/all", "CMD"));
            fabricInfoList.Add(new Command("arp -a", "ARP", "-a", "CMD"));
            fabricInfoList.Add(new Command("netstat -n", "netstat", "-n", "CMD"));
            fabricInfoList.Add(new Command("netstat -nasert", "netstat", "-nasert", "CMD"));
            fabricInfoList.Add(new Command("netstat -an", "netstat", "-an", "CMD"));
            fabricInfoList.Add(new Command("route", "route", "PRINT", "CMD"));
            fabricInfoList.Add(new Command("net use", "net", "use", "CMD"));
            
            
            //--------
            // file list
            fileList.Add(System.Environment.ExpandEnvironmentVariables("%HOMEDRIVE%") + "\\Windows\\System32\\LogFiles\\PerformanceTuning.log");
			
            //--------
            // smbInfoList
            smbInfoList.Add(new Command("Get-NetAdapter", "powershell", "\"Get-NetAdapter\"", "CMD"));
            smbInfoList.Add(new Command("Get-NetAdapterRSS", "powershell", "\"Get-NetAdapterRSS\"", "CMD"));
            smbInfoList.Add(new Command("Get-NetOffloadGlobalSetting", "powershell", "\"Get-NetOffloadGlobalSetting\"", "CMD"));
            smbInfoList.Add(new Command("Get-NetAdapterRDMA", "powershell", "\"Get-NetAdapterRDMA\"", "CMD"));
            smbInfoList.Add(new Command("ndinstall", "powershell", "\"ndinstall\"", "CMD"));
            smbInfoList.Add(new Command("Get-NetAdapterHardwareInfo", "powershell", "\"Get-NetAdapterHardwareInfo\"", "CMD"));
            smbInfoList.Add(new Command("Get-SmbClientConfiguration", "powershell", "\"Get-SmbClientConfiguration\"", "CMD"));
            smbInfoList.Add(new Command("Get-SmbClientNetworkInterface", "powershell", "\"Get-SmbClientNetworkInterface\"", "CMD"));
            smbInfoList.Add(new Command("Get-SmbServerConfiguration", "powershell", "\"Get-SmbServerConfiguration\"", "CMD"));
            smbInfoList.Add(new Command("Get-SmbServerNetworkInterface", "powershell", "\"Get-SmbServerNetworkInterface\"", "CMD"));
            smbInfoList.Add(new Command("Get-SmbConnection", "powershell", "\"Get-SmbConnection\"", "CMD"));
            smbInfoList.Add(new Command("Get-SmbMultichannelConnection", "powershell", "\"Get-SmbMultichannelConnection\"", "CMD"));
            smbInfoList.Add(new Command("Get-SmbMultichannelConnection -IncludeNotSelected", "powershell", "\"Get-SmbMultichannelConnection -IncludeNotSelected\"", "CMD"));
            smbInfoList.Add(new Command("netstat.exe -xan | ? {$_ -match \"445\"}", "powershell", "\"netstat.exe -xan | ? {$_ -match \"445\"}\"", "CMD"));
            //smbInfoList.Add(new Command("Get-", "powershell", "\"Get-\"", "CMD"));
            
            
            //--------
            // perfTestList
            perfTestList.Add(new Command("ibv_write_bw", "ibv_write_bw", "devName", "perfTest"));
            perfTestList.Add(new Command("ibv_write_lat", "ibv_write_lat", "devName", "perfTest"));
            

            //--------
            // Sort the tables
            sortCommandsArrayList(ref serverInfoList);
            sortCommandsArrayList(ref mlxRegValues);
            sortCommandsArrayList(ref eventLogsList);
            sortCommandsArrayList(ref fabricInfoList);
            sortCommandsArrayList(ref perfTestList);
            sortCommandsArrayList(ref smbInfoList);
            fileList.Sort();
            
            // - Build initial HTML
            buildInitialHTML();
            
            // add index tables
            addIndexTable("Server Information", serverInfoList);
            addIndexTable("Mellanox Registry Information", mlxRegValues);
            addIndexTable("System Event Logs", eventLogsList);
            addIndexTable("Fabric information", fabricInfoList);
            addIndexTable("Performance Tests", perfTestList);
            addIndexTable("SMB Information", smbInfoList);
            addIndexTable("Files", fileList);
            
        }// constructor
        //
        //-------------------------------------------------------------------------------------------
        //
        /// <summary>
        /// runs the commands and save the outputs in the HTML file.
        /// </summary>
        public void genHTML()
        {
            try
            {
                addCommandsResults(serverInfoList); //"Server information"
                addCommandsResults(eventLogsList);
                addCommandsResults(mlxRegValues);
                addCommandsResults(fabricInfoList);//"Fabric information"
                addCommandsResults(perfTestList);
                addCommandsResults(smbInfoList);
                addFileContent(fileList);
                
                // create the output HTML file.
                openStream();
                // finish the HTML file.
                finalizeHTMLFile(this.html.ToString());
                // close the file handle.
                closeStream();
                //
                isDone = true;
                if (!Program.IS_RUNNING_WITH_GUI)
                {
                    showMsg("The system snapshot file \"" + HTMLpath + "\" was created successfully!", "File Created");
                    System.Environment.Exit(0);
                }
            }
            catch
            { }
        }
        //
        //-------------------------------------------------------------------------------------------
        //
        /// <summary>
        /// create the output HTML file.
        /// </summary>
        private void openStream()
        {
            try
            {
                // Create file 
                outStream = new StreamWriter(HTMLpath);
            }
            catch(Exception ex)
            {
                showMsg("Could not create the system snapshot.\n" + ex.Message + "\n" + ex.InnerException, "Proccess stopped");
                System.Environment.Exit(0);
            }
        }
        //
        //-------------------------------------------------------------------------------------------
        //
        /// <summary>
        /// close the file handle.
        /// </summary>
        private void closeStream()
        {
            try
            {
                outStream.Close();
            }
            catch
            {
            }
        }
        //
        //-------------------------------------------------------------------------------------------
        //
        /// <summary>
        /// runs a command and adds the output to the HTML file.
        /// </summary>
        /// <param name="obj">the command to run</param>
        /// <param name="prevAnchorName">previous command (for navigating)</param>
        /// <param name="nextAnchorName">next command (for navigating)</param>
        private void getParsedQuery(Command obj, String prevAnchorName, String nextAnchorName)
        {
            String output = "";
            try
            { 
                // run the command and get the output
                if (!obj.getCommand().Equals("") && !obj.getType().Equals("REG") && !obj.getType().Equals("perfTest"))
                {
                	output = runCommand(obj.getCommand(), obj.getArguments());
                }
                // check if there was an error
                if (output.Contains("ERROR:"))
                {
                    appendToHTML(obj.getName(), obj.getAnchor(), output, prevAnchorName, nextAnchorName);
                    return;
                }
                //
                switch (obj.getType())
                {
                    case "REG":
                        {
                			String parsedOutput = readRegistryKey(obj.getCommand(), obj.getArguments()); //parseOutputFromRegistry(output);
                			if (parsedOutput == null)
                			{
                				parsedOutput = "The following Registry key was not found: " + obj.getCommand() + "\\" + obj.getArguments() + "\n";
                			}
                            appendToHTML(obj.getName(), obj.getAnchor(), parsedOutput, prevAnchorName, nextAnchorName);
                            break;
                        }
                    case "CMD":
                        {
                            appendToHTML(obj.getName(), obj.getAnchor(), output, prevAnchorName, nextAnchorName);
                            break;
                        }
                    case "mlxNetAdpList":
                        {
                            // gather information about the installed HCAs
                            appendToHTML(obj.getName(), obj.getAnchor(), getMlxAdaptersList(), prevAnchorName, nextAnchorName);
                            break;
                        }
                	case "generalRegistryValues":
                        {
                            // gather information about the interfaces
                            appendToHTML(obj.getName(), obj.getAnchor(), getGeneralRegistryValues(), prevAnchorName, nextAnchorName);
                            break;
                        }
                	case "mlxNetAdpSettings":
                        {
                            // gather information about the interfaces
                            appendToHTML(obj.getName(), obj.getAnchor(), getMlxAdaptersSettings(), prevAnchorName, nextAnchorName);
                            break;
                        }
                	case "queryViaMFT":
                		{
                			appendToHTML(obj.getName(), obj.getAnchor(), queryViaMFT(), prevAnchorName, nextAnchorName);
                            break;
                		}
                	case "perfTest":
                		{
                			appendToHTML(obj.getName(), obj.getAnchor(), runPerfTest(obj.getCommand(), obj.getArguments()), prevAnchorName, nextAnchorName);
                            break;
                		}
                	case "lspci":
                		{
                			output = runCommand(lspciPath, obj.getArguments());
                			appendToHTML(obj.getName(), obj.getAnchor(), output, prevAnchorName, nextAnchorName);
                            break;
                		}
                    case "tasklist":
                        {
                            String parsedOutput = "<table border=\"1\">";

                            parsedOutput += "<th>Image Name</th>";
                            parsedOutput += "<th>PID</th>";
                            parsedOutput += "<th>Session Name</th>";
                            parsedOutput += "<th>Session#</th>";
                            parsedOutput += "<th>Mem Usage</th>";
                            parsedOutput += "<th>Status</th>";
                            parsedOutput += "<th>User Name</th>";
                            parsedOutput += "<th>CPU Time</th>";
                            parsedOutput += "<th>Window Title</th>";

                            String[] lines = Regex.Split(output, "\r\n");
                            for (int i = 0 ; i < lines.Length ; i++)
                            {
                                parsedOutput += "<tr>";
                                string[] line = Regex.Split(lines[i], "\",\"");
                                for (int j = 0 ; j < line.Length ; j++)
                                {
                                    parsedOutput += "<td>" + Regex.Replace(line[j], "\"", "") + "</td>";
                                }
                                parsedOutput += "</tr>";
                            }
                            parsedOutput += "</table>";

                            appendToHTML(obj.getName(), obj.getAnchor(), parsedOutput, prevAnchorName, nextAnchorName);
                            break;
                        }
                    case "drivers":
                        {
                            String parsedOutput = "<table border=\"1\">";

                            String[] lines = Regex.Split(output, "\n");
                            // table headers 
                            String[] row = Regex.Split(lines[0], ",");
                            for (int j = 0; j < row.Length; j++)
                            {
                                parsedOutput += "<th>" + Regex.Replace(row[j], "\"", "") + "</th>";
                            }
                            // table content (rows)
                            for (int i = 1; i < lines.Length; i++)
                            {
                                row = Regex.Split(lines[i], "\",");
                                parsedOutput += "<tr>";
                                for (int j = 0; j < row.Length; j++)
                                {
                                    parsedOutput += "<td>" + Regex.Replace(row[j], "\"", "") + "</td>";
                                }
                                parsedOutput += "</tr>";
                            }
                            //
                            parsedOutput += "</table>";
                            // add it to the html file
                            appendToHTML(obj.getName(), obj.getAnchor(), parsedOutput, prevAnchorName, nextAnchorName);
                            break;
                        }
                }
            }
            catch(Exception ex)
            {
                appendToHTML(obj.getName(), obj.getAnchor(), output + "\n"+ ex.Message + "\n" + ex.InnerException, prevAnchorName, nextAnchorName);
            }
        }
        //
        //-------------------------------------------------------------------------------------------
        //
        /// <summary>
        /// appends a command's output
        /// </summary>
        /// <param name="propName">command's name</param>
        /// <param name="anchorName">link to the output</param>
        /// <param name="output">command's output</param>
        /// <param name="prevAnchorName">link to previous command</param>
        /// <param name="nextAnchorName">link to next command</param>
        private void appendToHTML(String propName, String anchorName, String output, String prevAnchorName, String nextAnchorName)
        {
            try
            {
                this.html.Append("<a name=\"").Append(anchorName).Append("\"></a>"); // link to the output

                this.html.Append("<a href=\"#").Append(prevAnchorName).Append("\">[<-- Previous ]</a>"); // prev
                this.html.Append("   <a href=\"#index\">[ Back to index ]</a>"); // index
                this.html.Append("   <a href=\"#").Append(nextAnchorName).Append("\">[ Next -->]</a>"); // next

                this.html.Append("<h2><u>").Append(propName).Append("</u></h2>");

             //   this.html.Append("<a href=\"#").Append(anchorName).Append("\" id=\"id_toggle_").Append(anchorName).Append("\" onclick=\"toggle('id_").Append(anchorName).Append("', this)\">Collapse</a>");
             //   this.html.Append("<div id=\"id_").Append(anchorName).Append("\" style=\"display:\">");
                this.html.Append(output);
                this.html.Append("</div>\n");
            }
            catch (Exception ex)
            {
                this.html.Append("\nerror "
                    + ex.Message + "\n"
                    + ex.InnerException);
            }
        }
        //
        //-------------------------------------------------------------------------------------------
        //
        /// <summary>
        /// parse output from Registry
        /// </summary>
        /// <param name="output"></param>
        /// <returns></returns>
        private String parseOutputFromRegistry(String output)
        {
            output = output.Substring(output.IndexOf("\n") + 1);
            String parsedOutput = output;
            try
            {
                if (output.Contains("REG_SZ"))
                {
                    String[] seperated = Regex.Split(output, "REG_SZ");
                    parsedOutput = seperated[1];
                }
                if (output.Contains("REG_MULTI_SZ"))
                {
                    String[] seperated = Regex.Split(output, "REG_MULTI_SZ");
                    parsedOutput = seperated[1];
                }
                if (output.Contains("REG_DWORD"))
                {
                    String[] seperated = Regex.Split(output, "REG_DWORD");
                    parsedOutput = seperated[1];
                    parsedOutput = HEX2DECstring(parsedOutput);
                }
            }
            catch(Exception ex)
            {
                return parsedOutput.ToString() 
                    + "\nerror "
                    + ex.Message + "\n"
                    + ex.InnerException;                    
            }
            return parsedOutput.ToString();
        }
        //
        //-------------------------------------------------------------------------------------------
        
        /// <summary>
        /// converts a HEX number to decimal
        /// </summary>
        /// <param name="hex2decNoWS"></param>
        /// <returns></returns>
        private String HEX2DECstring(String hex2decNoWS)
        {
            try
            {
                hex2decNoWS = hex2decNoWS.Replace(" ", "");
                hex2decNoWS = hex2decNoWS.Replace("\\s+", "");
                hex2decNoWS = hex2decNoWS.Replace("0x", "");
                return Int32.Parse(hex2decNoWS, System.Globalization.NumberStyles.HexNumber).ToString();
            }
            catch
            {
                return "";
            }
        }
        //
        //-------------------------------------------------------------------------------------------
        //
        /// <summary>
        /// gets a commands list and appends the output to the HTML file.
        /// </summary>
        /// <param name="list"></param>
        private void addCommandsResults(ArrayList list)
        {
            try
            {
                for (int i = 0; i < list.Count; i++)
                {
                    if (i == 0)
                    {
                        getParsedQuery((Command)list[i], "", ((Command)list[1]).getAnchor());
                    }
                    else
                    {
                        if (i == list.Count - 1)
                        {
                            getParsedQuery((Command)list[i], ((Command)list[i - 1]).getAnchor(), "");
                        }
                        else
                        {
                            getParsedQuery((Command)list[i], ((Command)list[i - 1]).getAnchor(), ((Command)list[i + 1]).getAnchor());
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                this.html.Append("\nerror "
                    + ex.Message + "\n"
                    + ex.InnerException + "\n");
            }
        }
        //
        //-------------------------------------------------------------------------------------------
        
        /// <summary>
        /// gets a file list and appends the content to the HTML file.
        /// </summary>
        /// <param name="list"></param>
        private void addFileContent(ArrayList list)
        {
        	try
            {
                for (int i = 0; i < list.Count; i++)
                {
                	string item = (string)list[i];
                   	item = item.Substring(item.LastIndexOf('\\')+1);
                    if (i == 0)
                    {
                    	if (i+1 < list.Count)
                    	{
                    		string next = (string)list[i+1];
                   			next = next.Substring(next.LastIndexOf('\\')+1);
                    		appendToHTML(item, Regex.Replace(item, " ", "_"), getFileContent((string)list[i]), "", Regex.Replace(next, " ", "_"));	
                    	}
                    	else
                    	{
                    		appendToHTML(item, Regex.Replace(item, " ", "_"), getFileContent((string)list[i]), "", "");	
                    	}
                    }
                    else
                    {
                        if (i == list.Count - 1)
                        {
                        	string prev = (string)list[i-1];
                   			prev = prev.Substring(prev.LastIndexOf('\\')+1);
                        	appendToHTML(item, Regex.Replace(item, " ", "_"), getFileContent((string)list[i]), Regex.Replace(prev, " ", "_"), "");	
                        }
                        else
                        {
                        	string next = (string)list[i+1];
                   			next = next.Substring(next.LastIndexOf('\\')+1);
                            string prev = (string)list[i-1];
                   			prev = prev.Substring(prev.LastIndexOf('\\')+1);
                   			appendToHTML(item, Regex.Replace(item, " ", "_"), getFileContent((string)list[i]), Regex.Replace(prev, " ", "_"), Regex.Replace(next, " ", "_"));
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                this.html.Append("\nerror "
                    + ex.Message + "\n"
                    + ex.InnerException + "\n");
            }
        }
        //
        //-------------------------------------------------------------------------------------------
        
        /// <summary>
        /// gets the content of a file
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        private string getFileContent(string path)
        {
        	try
        	{
	        	StreamReader sr = new StreamReader(path);
	        	string res = sr.ReadToEnd();
	        	sr.Close();
	        	return res;
        	}
        	catch (Exception ex)
            {
                return "\nerror "
                    + ex.Message + "\n"
                    + ex.InnerException + "\n";
            }
        }
        //
        //-------------------------------------------------------------------------------------------
        
        /// <summary>
        /// add the header and JavaScript fucntions (for expanding/collapsing the output).
        /// </summary>
        private void buildInitialHTML()
        {
            try
            {
                this.html.Append("<html><meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\"><head><title>System Snapshot</title>\n");
                this.html.Append("</head><body><pre>");

//                this.html.Append("<script type=\"text/javascript\"> function toggle(id, link) {  var e = document.getElementById(id);  if (e.style.display == '') { e.style.display = 'none'; link.innerHTML = 'Expand';  } else {  e.style.display = ''; link.innerHTML = 'Collapse'; }} </script>");
//
//                this.html.Append("<script type=\"text/javascript\">");
//
//                // -----------
//                // build array of all the ids of the output div
//                string ids = "";
//                for (int i = 0; i < serverInfoList.Count; i++)
//                {
//                    ids += "'id_" + ((Command)serverInfoList[i]).getAnchor() + "'";
//                    if (i + 1 < serverInfoList.Count)
//                    {
//                        ids += ", ";
//                    }
//
//                }
//                if (fabricInfoList.Count > 0)
//                {
//                    ids += ", ";
//                }
//                for (int i = 0; i < fabricInfoList.Count; i++)
//                {
//                    ids += "'id_" + ((Command)fabricInfoList[i]).getAnchor() + "'";
//                    if (i + 1 < fabricInfoList.Count)
//                    {
//                        ids += ", ";
//                    }
//                }
//                
//                // -----------
//                // -----------
//                // build array of all the ids of the Expand/Collaps buttons
//                string ids_toggle = "";
//                for (int i = 0; i < serverInfoList.Count; i++)
//                {
//                    ids_toggle += "'id_toggle_" + ((Command)serverInfoList[i]).getAnchor() + "'";
//                    if (i + 1 < serverInfoList.Count)
//                    {
//                        ids_toggle += ", ";
//                    }
//
//                }
//                if (fabricInfoList.Count > 0)
//                {
//                    ids_toggle += ", ";
//                }
//                for (int i = 0; i < fabricInfoList.Count; i++)
//                {
//                    ids_toggle += "'id_toggle_" + ((Command)fabricInfoList[i]).getAnchor() + "'";
//                    if (i + 1 < fabricInfoList.Count)
//                    {
//                        ids_toggle += ", ";
//                    }
//                }
//                // -----------
//
//                this.html.Append("var ids = new Array(").Append(ids).Append(");");
//                this.html.Append("var ids_toggle = new Array(").Append(ids_toggle).Append(");");
//
//                this.html.Append(" function collapsAll()"
//                    + "{  	for (var i=0;i<ids.length;i++){"
//                    + "		document.getElementById(ids[i]).style.display = 'none';"
//                    + "	}	for (var i=0;i<ids_toggle.length;i++){"
//                    + "		document.getElementById(ids_toggle[i]).innerHTML = 'Expand';	} }"
//                    + " function expandAll()"
//                    + " {  	for (var i=0;i<ids.length;i++){"
//                    + "		document.getElementById(ids[i]).style.display = '';	}"
//                    + "	for (var i=0;i<ids_toggle.length;i++){"
//                + "document.getElementById(ids_toggle[i]).innerHTML = 'Collapse';"
//                + "	} } </script>");

                // link to the top of the page
                this.html.Append("<a name=\"index\"></a>");

                this.html.Append("<h1>Mellanox Technologies</h1>");
                this.html.Append("<h2>Mellanox Windows System Information Snapshot Utility</h2>");
                Assembly assembly = Assembly.GetExecutingAssembly();
				FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
				string version = fvi.ProductVersion;
                this.html.Append("<h3>Version: " + version + "</h3>");
                this.html.Append("<hr>\n\n");
             //   this.html.Append("\n<a href=\"#\" onclick=\"collapsAll()\">Collapse all</a>");
             //   this.html.Append("  |  <a href=\"#\" onclick=\"expandAll()\">Expand all</a>\n\n<hr>");
            }
            catch (Exception ex)
            {
                this.html.Append("error "
                    + ex.Message + "\n"
                    + ex.InnerException);
            }
        }
        //
        //-------------------------------------------------------------------------------------------
        //
        /// <summary>
        /// adds the commands from a list to the index table.
        /// </summary>
        /// <param name="title"></param>
        /// <param name="list"></param>
        private void addIndexTable(String title, ArrayList list)
        {
            try
            {
                this.html.Append("<h2>").Append(title).Append("</h2>");
                // add the index table
                this.html.Append("<table cols=\"").Append(COLUMNS).Append("\" width=\"100%\" border=\"0\" bgcolor=\"#E0E0FF\"><tbody><tr>\n");
				
                int rowCount = (list.Count / COLUMNS) + ((list.Count % COLUMNS) > 0 ? 1 : 0);
                int r = 0, c = 0;
                
                for (int i = 0; i < list.Count; i++)
                {
                	int jj = r + c * rowCount;
                	if (jj < list.Count)
                	{
	                	if (list[jj] is Command)
	                	{
	                    	Command item = (Command)list[jj];
	                    	this.html.Append("<td width=\"").Append(100 / COLUMNS).Append("%\">").Append(item.getHref()).Append("</td>\n");
	                	}
	                	else
	                	{
	                		string item = (string)list[jj];
	                		item = item.Substring(item.LastIndexOf('\\')+1);
	                		string href = "<a href=\"#" + Regex.Replace(item, " ", "_") + "\">" + item + "</a>";
	                		this.html.Append("<td width=\"").Append(100 / COLUMNS).Append("%\">").Append(href).Append("</td>\n");
	                	}
                	}
                	else
                	{
                		i--;
                	}
                	//
                	c++;
                	if (c == COLUMNS)
                    {
                    	this.html.Append("</tr><tr>"); // end row
                    	c = 0;
                    	r++;
                    }
                }
                this.html.Append("</tr></tbody></table>\n");
            }
            catch (Exception ex)
            {
            	this.html.Append("</tr></tbody></table>\n");
                this.html.Append("error "
                    + ex.Message + "\n"
                    + ex.InnerException);
            }
        }
        //
        //-------------------------------------------------------------------------------------------
        //
        /// <summary>
        ///  close the header and body
        /// </summary>
        /// <param name="htmlText"></param>
        private void finalizeHTMLFile(String htmlText)
        {
            try
            {
                this.html.Append("</pre></body>");
                this.html.Append("</html>");
                outStream.Write(htmlText);
            }
            catch (Exception ex)
            {
                this.html.Append("error "
                    + ex.Message + "\n"
                    + ex.InnerException);
            }
        }
        //
        //-------------------------------------------------------------------------------------------
        //
        /// <summary>
        /// gather information about the installed HACs
        /// </summary>
        /// <returns></returns>
        private String getMlxAdaptersList()
        {
            String output = "** Note: The below information was retrieved from the Registry.\n";
            try
            {
                String mlx4_busEnum = "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\services\\mlx4_bus\\Enum";                
                String ENUM = "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\ENUM";
                String CLASS = "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\class";

                String tmp = readRegistryKey(mlx4_busEnum, "Count");
                if (tmp == null)
                {
                	return "<b>Couldn't locate Mellanox cards in this system!</b>";	
                }
                int deviceCount = Int32.Parse(tmp); // number of installed devices in the system

 				/* ###############################################################
 				 * get basic info about each card
 				 * */
                for (int i = 0; i < deviceCount; i++)
                { // for all the devices
                    String pciPath = readRegistryKey(mlx4_busEnum, i.ToString());
                    if (!pciPath.Contains("Root"))
                    {
	                    String pci = ENUM + "\\" + pciPath;// + "\"";
	
	                    String driverPath = readRegistryKey(pci, "Driver");
	                    String driver = CLASS + "\\" + driverPath;// + "\"";
	
	                    String location = readRegistryKey(pci, "LocationInformation");
	
	                    String description = readRegistryKey(pci, "DeviceDesc");
	                    description = description.Substring(description.IndexOf(';') + 1);
	
	                    String driverDate = readRegistryKey(driver, "DriverDate");
	
	                    String CapabilityFlag = readRegistryKey(driver + "\\Parameters", "CapabilityFlag");
	                    String roce = readRegistryKey(driver + "\\Parameters", "EnableRoce");
	                    String portType = readRegistryKey(driver + "\\Parameters", "PortType");
	                    String providerName = readRegistryKey(driver, "ProviderName");
	
	                    String driverVersion = readRegistryKey(driver, "DriverVersion");
	
	                    CapabilityFlag = removeNLS(CapabilityFlag);
	                    CapabilityFlag = Convert.ToString(Int32.Parse(CapabilityFlag), 2);
	                    //make sure CapabilityFlag has 11 bits
	                    while (CapabilityFlag.Length < 11)
	                    {
	                        CapabilityFlag = "0" + CapabilityFlag;
	                    }
	
	                    String[] vstat = Regex.Split(runCommand("vstat", ""), "\n");
	                    String fwVer = "";
	                    String psid = "";
	                    try
	                    {
		                    for (int j = 0; j < vstat.Length; j++)
		                    {
		                        if (vstat[j].Contains("hca_idx=" + i))
		                        {
		                            fwVer = vstat[j + 6].Split('=')[1];
		                            psid = vstat[j + 7].Split('=')[1];
		                        }
		                    }
	                    }
	                    catch{}
	                    
	                    output += "\n----------------------------------------------\n";
	
	                    output += "Provider name:  " + providerName + "\n";
	                    output += "Description: " + description + "\n";
	                    output += "Number of ports: " + (Int32.Parse((CapabilityFlag[10].ToString())) + 1) + "\n";
	                    output += "Driver version: " + driverVersion + "\n";
	                    output += "Driver Date: " + driverDate + "\n";
	                    output += "Firmware version: " + fwVer + "\n";
	                    output += "PSID: " + psid + "\n";
	                    output += "Location: " + location + "\n";
	                    output += "Ports info:\n";
	                    output += "<table border=\"1\">";
	                    output += "<th> </th>";
	                    output += "<th>Port 1</th>";
	                    output += "<th>Port 2</th>";
	
	                    output += "<tr>";
	                    output += "<td><b>Current Port type</b></td>";
	                    if (portType!= null && !portType.Equals("") && !portType.Contains("ERROR"))
	                    {
	                        portType = portType.ToUpper();
	                        String[] portTypes = portType.Split(',');
	                        for (int jj = 0; jj < portTypes.Length; jj++)
	                        {
	                            output += "<td>" + portTypes[jj] + "</td>";
	                        }
	                    }
	                    else
	                    {
	                        output += "<td>" + bin2IBETH(CapabilityFlag[1]) + "</td>"; // what about one port cards?
	                        output += "<td>" + bin2IBETH(CapabilityFlag[0]) + "</td>";
	                    }
						output += "</tr>";
	
	                    output += "<tr>";
	                    output += "<td>ROCE enabled</td>";
	                    roce = removeNLS(roce);
	                    String[] roceArr = roce.Split(',');
	                    for (int jj = 0; jj < roceArr.Length; jj++)
	                    {
	                        output += "<td>" + bin2YESNO(roceArr[jj][0]) + "</td>";
	                    }
	                    output += "</tr>";
	
	                    output += "<tr>";
	                    output += "<td>Port can be IB</td>";
	                    output += "<td>" + bin2YESNO(CapabilityFlag[9]) + "</td>";
	                    output += "<td>" + bin2YESNO(CapabilityFlag[8]) + "</td>";
	                    output += "</tr>";
	
	                    output += "<tr>";
	                    output += "<td>Port can be ETH</td>";
	                    output += "<td>" + bin2YESNO(CapabilityFlag[7]) + "</td>";
	                    output += "<td>" + bin2YESNO(CapabilityFlag[6]) + "</td>";
	                    output += "</tr>";
	
	                    output += "<tr>";
	                    output += "<td>Port Do Sense Allowed</td>";
	                    output += "<td>" + bin2YESNO(CapabilityFlag[5]) + "</td>";
	                    output += "<td>" + bin2YESNO(CapabilityFlag[4]) + "</td>";
	                    output += "</tr>";
	
	                    output += "<tr>";
	                    output += "<td>Port Auto Sense Cap</td>";
	                    output += "<td>" + bin2YESNO(CapabilityFlag[3]) + "</td>";
	                    output += "<td>" + bin2YESNO(CapabilityFlag[2]) + "</td>";
	                    output += "</tr>";
	
	                    output += "<tr>";
	                    output += "<td>Port Default type</td>";
	                    output += "<td>" + bin2IBETH(CapabilityFlag[1]) + "</td>";
	                    output += "<td>" + bin2IBETH(CapabilityFlag[0]) + "</td>";
	                    output += "</tr>";
	
	                    output += "</table>";
                    }
                    
                } // end of for
                /* ###############################################################
 				 * end of: get basic info about each card
 				 * */
 				
                return output;
            }
            catch (Exception ex)
            {
                return output +
                    "\nerror "
                    + ex.Message + "\n"
                    + ex.InnerException + "\n";
            }
        }
        //
        //-------------------------------------------------------------------------------------------
        
        /// <summary>
        /// gather information about the interfaces
        /// </summary>
        /// <returns></returns>
        private string getMlxAdaptersSettings()
        {
        	String output = "** Note: The below information was retrieved from the Registry.\n";
        	output += "Detailed information about each Registry Property can be found in the <a href =\"http://www.mellanox.com/page/products_dyn?product_family=32&mtag=windows_sw_drivers\">'MLNX WinOF VPI Registry Keys'</a> document.\n\n";
        	try
        	{
        		/* ###############################################################
				 * Get all relevant settings for each port 
				 * */
				String ipoibPorts_Enum = getIPoIBServicePath() + "\\Enum";
				String ethPorts_Enum = getMlx4ethServicePath() + "\\Enum";

	            /* -----------------------------
				 *  Scan Eth ports 
				 */
	            // get the number of Eth ports
	            string tmpCount = readRegistryKey(ethPorts_Enum, "Count");
	            if (tmpCount != null)
	            {
		            int ethPortCount = Int32.Parse(tmpCount);
	                for (int zz = 0 ; zz < ethPortCount ; zz++)
	                {
	                	string portEnumPath = readRegistryKey(ethPorts_Enum, zz.ToString());
	                	if (!portEnumPath.Contains("Root"))
	                	{
		                	output += "\n----------------------------------------------\n";
		                	output += getPortInfo(portEnumPath);	
	                	}
	                }
	            }
	            else
	            {
	            	output += "<b>Couldn't locate Mellanox Ethernet interfaces.</b>\n";
	            }
	            /* -----------------------------
				 *  Scan IB (IPoIB) ports
				 */ 
                // get the number of IPoIB ports
                tmpCount = readRegistryKey(ipoibPorts_Enum, "Count");
                if (tmpCount != null)
                {
	                int ipoibPortCount = Int32.Parse(tmpCount); 
	                for (int zz = 0 ; zz < ipoibPortCount ; zz++)
	                {
	                	string portEnumPath = readRegistryKey(ipoibPorts_Enum, zz.ToString());
	                	if (!portEnumPath.Contains("Root"))
	                	{
		                	output += "\n----------------------------------------------\n\n";
		                	output += getPortInfo(portEnumPath);	
	                	}
	                }
                }
                else
	            {
	            	output += "<b>Couldn't locate Mellanox IPoIB interfaces.</b>\n";
	            }
                /* ###############################################################
                 * end of: Get all relevant settings for each port
				 * */
        	     
				return output;
            }
            catch (Exception ex)
            {
                return output +
                    "\nerror "
                    + ex.Message + "\n"
                    + ex.InnerException + "\n";
            }
        }
        //
        //-------------------------------------------------------------------------------------------
        
        /// <summary>
        /// get info and settings of a port
        /// </summary>
        /// <param name="path">path to the port in the Registry</param>
        /// <returns></returns>
        string getPortInfo(string enumPath)
        {
        	string res = "";
        	try
        	{
        		// info from the Enum
		        String enumFullPath = "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\ENUM" + "\\" + enumPath;
		        res += "Network Adapter name: <b>" + readRegistryKey(enumFullPath, "FriendlyName") + "</b>\n";
		        res += "Basic HW info:\n";
		        res += "\tService: " + readRegistryKey(enumFullPath,"Service") + "\n";
		        res += "\tHardware ID: " + readRegistryKey(enumFullPath, "HardwareID") + "\n";
		        res += "\tLocation Information: " + readRegistryKey(enumFullPath,"LocationInformation") + "\n";
		        String driverFullPath = "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\class\\" + readRegistryKey(enumFullPath, "Driver");
		        res += "\tDriver settings Registry location: " + "\n\t\t"+ enumFullPath + "\n\t\t" + driverFullPath + "\n";
		        		        
						        
				// info from Services\Tcpip
		        string netCfgInstanceId = readRegistryKey(driverFullPath, "NetCfgInstanceId");
		        if (netCfgInstanceId != null)
		        {
		        	string interfacePath = "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\" + netCfgInstanceId;
			        res += "\nInterface:\n";
			        res += "\tIPv4 Address: " + readRegistryKey(interfacePath, "IPAddress") + "\n";
			        res += "\tSubnet Mask: " + readRegistryKey(interfacePath, "SubnetMask") + "\n";
			        res += "\tDNS server addresses: " + readRegistryKey(interfacePath, "NameServer") + "\n";
			        res += "\tDefault Gateway: " + readRegistryKey(interfacePath, "DefaultGateway") + "\n";
		        }
		        // info from the Class
		        
		        string paramDescPath = "";
				// if win2012
				if (System.Environment.OSVersion.Version.Major == 6 && System.Environment.OSVersion.Version.Minor == 2)
				{
					paramDescPath = driverFullPath + "\\NDI\\Params";
				}
				else // if 2008r2/win7
				{
					paramDescPath = driverFullPath + "\\Ndi\\config";
				}

				// get all parameters
				string tmp = runCommand("reg", "query \"" + driverFullPath + "\"");
            	// get lines
            	string[] lines = Regex.Split(tmp, "\n");
            	tmp = "";
            	string paramDesc = runCommand("reg", "query \"" + paramDescPath + "\"");
            	
				res += "\n<table border=\"1\">";
				res += "<th>Property</th>";
				res += "<th>Value</th>";
				res += "<th>Value Description</th>";
				res += "<th>Property Description</th>";
				res += "<th>Default value</th>";
            	// get the value line
            	for (int i = 0 ; i < lines.Length ; i++)
            	{
            		if (lines[i].Contains("REG_SZ") || lines[i].Contains("REG_DWORD"))
            		{
						res += "<tr>"; // Start row
						
						string prop = getNameOfRegUtilResLine(lines[i]);
						res += "<td>" + prop + "</td>";
						string val = getValueOfRegUtilResLine(lines[i]);
						res += "<td>" + val + "</td>";
						if (paramDesc.Contains(prop))
						{
							res += "<td>" + readRegistryKey(paramDescPath+"\\"+prop+"\\enum", val) + "</td>";
							res += "<td>" + readRegistryKey(paramDescPath+"\\"+prop, "ParamDesc") + "</td>";
							res += "<td>" + readRegistryKey(paramDescPath+"\\"+prop, "Default") + "</td>";
						}
					
						res += "</tr>"; // end row
					}
				}
				res += "</table>";
		        
		        return res;
        	}
        	catch (Exception ex)
        	{
        		return res
        			+ "\n\nerror "
                    + ex.Message + "\n"
                    + ex.InnerException;
        	}
        }
        //
        //-------------------------------------------------------------------------------------------
        
        
        /// <summary>
		/// gets a parameter's value from the registry.
		/// </summary>
		/// <param name="key"></param>
		/// <param name="property"></param>
		/// <returns>value of property. if property is null it returns a list of all the properties and their values. and null if property is not found.</returns>
		private string readRegistryKey(string key, string property)
		{
			int firstSlash = key.IndexOf('\\');
			// get the base Key
			string baseKey = "";
			if (firstSlash >= 0)
			{	
				baseKey = key.Substring(0, firstSlash);
			}
			// open the desired key
			RegistryKey rk = null;
			switch(baseKey)
			{
				case "HKEY_LOCAL_MACHINE":
					key = key.Substring(firstSlash);
					key = key.TrimStart('\\');
					rk = Registry.LocalMachine.OpenSubKey(key);
					break;
			}
			// 
			if (rk != null)
			{
				// get the property
				if (property != null && !property.Equals(""))
				{
					return parseRegVal(rk, property);
				}
				else // if the property was not specified, return all the properties
				{
					string res = "";
					foreach(string valueName in rk.GetValueNames())
					{
						string val = parseRegVal(rk, valueName);
						if (val != null)
						{
							res += valueName + ": " + val + "\n";
						}
					}
					return res;
				}
			}
			else
			{
				return null;
			}
		}
		//
        //-------------------------------------------------------------------------------------------
        
		/// <summary>
		/// parse the value of a property if needed
		/// </summary>
		/// <param name="rk"></param>
		/// <param name="valueName"></param>
		/// <returns></returns>
		private string parseRegVal(RegistryKey rk, string valueName)
		{
			object val = rk.GetValue(valueName);
			if (val != null)
			{
				switch (rk.GetValueKind(valueName))
				{
					case RegistryValueKind.DWord:
						//retun HEX2DECstring(val.ToString());
						return val.ToString();
					case RegistryValueKind.String: // REG_SZ
						return val.ToString();
					case RegistryValueKind.MultiString: // REG_MULTI_SZ
						string res = "";
						string[] arr = (string[])val;
						for (int i=0 ; i < arr.Length ; i++)
						{
							res += arr[i] + " ";
						}
						return res;
					default:
						return null;
				}
			}
			else
			{
				return null;
			}			
		}
		//
        //-------------------------------------------------------------------------------------------
        
        
        /// <summary>
        /// gets registry values that affect the Mellanox driver operation
        /// </summary>
        /// <returns></returns>
        private string getGeneralRegistryValues()
        {
        	String output = "** Registry values that affect the Mellanox driver operation.\n\n";
        	try
        	{
        		output += "Rx ring Number: " + readRegistryKey(@"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\NDIS\Parameters", "MaxNumRssCpus") + "\n";
	            output += "RSS Base CPU: " + readRegistryKey(@"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\NDIS\Parameters", "RssBaseCpu") + "\n";
	            output += "Maximum Working Thread: " + readRegistryKey(getMlx4ethServicePath() + @"\Parameters", "MaximumWorkingThreads") + "\n";
	            
				return output;
            }
            catch (Exception ex)
            {
                return output +
                    "\nerror "
                    + ex.Message + "\n"
                    + ex.InnerException + "\n";
            }
        }
        //
        //-------------------------------------------------------------------------------------------
        	
//        /// <summary>
//        /// obsolete.... gets a parameter's value from the registry.
//        /// </summary>
//        /// <param name="path">Registry path to the parameter</param>
//        /// <param name="parameter">parameter</param>
//        public string getRegistryParameterValue(string path, string parameter)
//        {
//        	try
//            {
//        		
//        		
//        		string tmp = runCommand("reg", "query \"" + path + "\" /v " + parameter);
//            	// check for error
//            	if (tmp.Contains("ERROR") || tmp.Contains("0 match"))
//            	{
//            		// return null for error
//            		return null;
//            	}
//            	// get lines
//            	string[] lines = Regex.Split(tmp, "\n");
//            	tmp = "";
//            	
//            	// get the value line
//            	for (int i = 0 ; i < lines.Length ; i++)
//            	{
//            		if (lines[i].Contains(parameter+" "))
//            		{
//            			// get the line
//            			tmp = lines[i];
//            			// stop the loop
//            			break;
//            		}
//            	}
//            	
//            	if (!tmp.Equals(""))
//            	{
//	                // return value
//	                return getValueOfRegUtilResLine(tmp);
//            	}
//            	else
//            	{
//            		// return null for error
//            		return null;
//            	}
//            }
//            catch
//            {
//            	return null;
//            }
//        }
//        //
//        //-------------------------------------------------------------------------------------------
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="line"></param>
        /// <returns></returns>
        private string getValueOfRegUtilResLine(string line)
        {
        	// trim spaces at the start and end
        	line = Regex.Replace(line, "\n|\r", "");
            // get the value
            if (line.Contains("REG_SZ"))
            {
            	line = Regex.Split(line, "REG_SZ")[1];
            }
            if (line.Contains("REG_DWORD"))
            {
                line = Regex.Split(line, "REG_DWORD")[1];
                line = HEX2DECstring(line);
            }
            if (line.Contains("REG_MULTI_SZ"))
            {
            	line = Regex.Split(line, "REG_MULTI_SZ")[1];
            }
            line = line.TrimStart(' ');
            line = line.TrimEnd(' ');
            
            return line;
        }
	    //
        //-------------------------------------------------------------------------------------------
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="line"></param>
        /// <returns></returns>
        private string getNameOfRegUtilResLine(string line)
        {
        	// trim spaces at the start and end
        	line = Regex.Replace(line, "\n|\r", "");
            // get the value
            if (line.Contains("REG_SZ"))
            {
            	line = Regex.Split(line, "REG_SZ")[0];
            }
            if (line.Contains("REG_DWORD"))
            {
                line = Regex.Split(line, "REG_DWORD")[0];
            }
            if (line.Contains("REG_MULTI_SZ"))
            {
            	line = Regex.Split(line, "REG_MULTI_SZ")[0];
            }
            line = line.TrimStart(' ');
            line = line.TrimEnd(' ');
            
            return line;
        }
	    //
        //-------------------------------------------------------------------------------------------
        
        /// <summary>
        /// removes the "\n", "\r" and spaces from a string.
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        private String removeNLS(String str)
        {
            try
            {
                str = str.Replace("\n", "");
                str = str.Replace("\r", "");
                return str.Replace(" ", "");
            }
            catch
            {
                return "";
            }
        }
        //
        //-------------------------------------------------------------------------------------------
        //
        /// <summary>
        /// converts 1 -> YES, and 0 -> NO
        /// </summary>
        /// <param name="ch"></param>
        /// <returns></returns>
        private String bin2YESNO(char ch)
        {
            try
            {
                if (ch == '1')
                {
                    return "YES";
                }
                else
                {
                    return "NO";
                }
            }
            catch
            {
                return "";
            }
        }
        //
        //-------------------------------------------------------------------------------------------
        //
        /// <summary>
        /// converts 1 -> ETH, and 0 -> IB
        /// </summary>
        /// <param name="ch"></param>
        /// <returns></returns>
        private String bin2IBETH(char ch)
        {
            try
            {
                if (ch == '1')
                {
                    return "ETH";
                }
                else
                {
                    return "IB";
                }
            }
            catch
            {
                return "";
            }
        }
        //
        //-------------------------------------------------------------------------------------------
        //
        /// <summary>
        /// runs a command and returns the output. the command will be terminated after "timeOutSec" seconds.
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        protected virtual String runCommand(String command, string arguments)
        {
            StringBuilder output = new StringBuilder();
            StringBuilder errors = new StringBuilder();
            try
            {
                // update the processed command to be displayed in the GUI.
                this.proccessedCommand = command + " " + arguments;

                using (Process process = new Process())
                {
                    process.StartInfo.FileName = command;
                    process.StartInfo.Arguments = arguments;
                    process.StartInfo.CreateNoWindow = true;
                    process.StartInfo.UseShellExecute = false;
                    process.StartInfo.RedirectStandardOutput = true;
                    process.StartInfo.RedirectStandardInput = true;
                    process.StartInfo.RedirectStandardError = true;

                    // add delegate for the output
                    process.OutputDataReceived += (sender, e) =>
                    {
                        if (e.Data != null)
                        {
                            output.AppendLine(e.Data);
                        }
                    };
                    // add delegate for the errors
                    process.ErrorDataReceived += (sender, e) =>
                    {
                        if (e.Data != null)
                        {
                            errors.AppendLine(e.Data);
                        }
                    };
                    //
                    process.Start();
                    process.BeginOutputReadLine();
                    process.BeginErrorReadLine();

                    // timeout
                    int timeoutParts = 10;
                    int timeoutPart = (int)timeOutSec * 1000 / timeoutParts;
                    do
                    {
                        Thread.Sleep(500);
                        process.StandardInput.WriteLine("exit");
                        timeoutParts--;
                    }
                    while (!process.WaitForExit(timeoutPart) && timeoutParts > 0);

                    if (timeoutParts <= 0)
                    {
                        output.AppendLine("Timeout: The command was interrupted.");
                        process.Kill();
                    }

                    string result = output.ToString();
                    result += "\n\n" + errors.ToString();
                    return result;
                }
            }
            catch (Exception ex)
            {
                return output.ToString() + "\n"
                    + "error:\n"
                    + errors.ToString() + "\n"
                    + ex.Message + "\n"
                    + ex.InnerException;
            }
        }
        //
        //-------------------------------------------------------------------------------------------
        //
        /// <summary>
        /// Starts the process in the same thread (for the Console version)
        /// </summary>
        /// <param name="HTMLpath"></param>
        public void startNoNewThread(string HTMLpath)
        {
            try
            {
                this.HTMLpath = HTMLpath;
                this.genHTML();
            }
            catch (Exception ex)
            {
                showMsg("Could not generate HTML.\n " + ex.Message + "\n " + ex.InnerException, "Proccess stopped");
            }
        }
        //
        //-------------------------------------------------------------------------------------------
        //
        /// <summary>
        /// Starts the process in a NEW thread (for the GUI version)
        /// </summary>
        /// <param name="HTMLpath"></param>
        public void startNewThread(string HTMLpath)
        {
            try
            {
                this.HTMLpath = HTMLpath;
                ThreadStart ths = new ThreadStart(this.genHTML);
                myThread = new Thread(ths);
                myThread.Start();
            }
            catch(Exception ex)
            {
                showMsg("Could not generate HTML.\n " + ex.Message + "\n " + ex.InnerException, "Proccess stopped");
            }
        }
        //
        //-------------------------------------------------------------------------------------------
        //
        /// <summary>
        /// for the GUI version: Stops the new thread that is handling the process.
        /// </summary>
        public void stopThread()
        {
            try
            {
                closeStream();
                if (myThread != null && myThread.IsAlive)
                {
                    myThread.Abort();
                }
            }
            catch { }
        }
        //
        //-------------------------------------------------------------------------------------------
        //
        /// <summary>
        /// gets the command that is currently being processed.
        /// </summary>
        /// <returns></returns>
        public String getProccessedCommand()
        {
            return proccessedCommand;
        }
        //
        //-------------------------------------------------------------------------------------------
        //
        /// <summary>
        /// gets the value of the timeout
        /// </summary>
        /// <returns></returns>
        public int getTimeOut()
        {
            return timeOutSec;
        }
        //
        //-------------------------------------------------------------------------------------------
        //
        /// <summary>
        /// sets the timeout
        /// </summary>
        /// <param name="timeOut"></param>
        /// <returns></returns>
        public bool setTimeOut(int timeOut)
        {
            if (timeOut > 0)
            {
                timeOutSec = timeOut;
                return true;
            }
            else
            {
                return false;
            }
        }
        //
        //-------------------------------------------------------------------------------------------
        //
        /// <summary>
        /// abstract function for displaying messages.
        /// </summary>
        /// <param name="content"></param>
        /// <param name="title"></param>
        abstract public void showMsg(String content, String title);
        //
        //-------------------------------------------------------------------------------------------
        //
        
        /// <summary>
        /// gets the registry path for the mlx4eth service
        /// </summary>
        private string getMlx4ethServicePath()
        {
        	// if windows 2012
			if (System.Environment.OSVersion.Version.Major == 6 && System.Environment.OSVersion.Version.Minor == 2)
			{
				return "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\services\\mlx4eth63";
			}
			else 
			{
				 // if windows 2008R2/Windows7
				if (System.Environment.OSVersion.Version.Major == 6 && System.Environment.OSVersion.Version.Minor == 1)
				{
					return "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\services\\mlx4eth6";
				}
				else
				{
					// if Windows 2008
					return "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\services\\mlx4eth61";
				}
			}
        }
        //-------------------------------------------------------------------------------------------
        //
        
        /// <summary>
        /// gets the registry path for the IPoIB service
        /// </summary>
        private string getIPoIBServicePath()
        {
        	// if windows 2012
			if (System.Environment.OSVersion.Version.Major == 6 && System.Environment.OSVersion.Version.Minor == 2)
			{
				return "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\ipoib6x";
			}
			else 
			{
				 // if windows 2008R2/Windows7
				if (System.Environment.OSVersion.Version.Major == 6 && System.Environment.OSVersion.Version.Minor == 1)
				{
					return "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\xoib62";
				}
				else
				{
					// if Windows 2008
					return "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\xoib61";
				}
			}
        }
        //-------------------------------------------------------------------------------------------
        //
        
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        private string queryViaMFT()
        {
        	string output = "";
        	String mstStatus = "";
        	// start mst 
        	mstStatus = runCommand("mst", "start");
        	if (mstStatus.Contains("error")) 
        	{
        		return "MFT is not installed on this server.";
        	}
        	// get MST devices
        	mstStatus += "\n\n" + runCommand("mst", "status");
			String[] mstStatusLines = Regex.Split(mstStatus, "\n");
        	
			// query all devices        	
			for (int i=0 ; i < mstStatusLines.Length ; i++)
			{
				if (mstStatusLines[i].Contains("pciconf"))
				{
					string mstDev = Regex.Replace(mstStatusLines[i], "\r|\n| ", "");
					output += runCommand("flint", "-d " + mstDev + " q");
					output += "\n-----------------------------------------------------\n\n";
				}
			}
			
			if (output.Equals(""))
			{
				output = mstStatus; 
			}
			
			// return output
        	return output;
        }
    	//-------------------------------------------------------------------------------------------
        //
        
        /// <summary>
        /// runs a perfromace test
        /// </summary>
        /// <param name="test"></param>
        /// <returns></returns>
        private string runPerfTest(string test, string dParam)
        {
        	string output = "";
        	try
        	{
	        	//
	        	// check if the user entered the server IP address and the IB card info
	        	//
	        	if (perfConfig == null)
	        	{
	        		return "The settings for the performance tests were not entered.";
	        	}
	        	// check if the test was enabled in the GUI
	        	if (!perfConfig.runPerfTests)
	        	{
	        		return "The performance tests were not enabled.";
	        	}
	        	//
	        	string param = "";
	        	if (dParam.Equals("devName"))
	        	{
	        		 param = "-d " + perfConfig.clinetIbDevName + " -i " + perfConfig.clinetIbPortNum;
	        	}
	        	if (dParam.Equals("devGuid"))
	        	{
	        		 param = "-d " + perfConfig.clinetIbDevGuid + " -i " + perfConfig.clinetIbPortNum;
	        	}	
	        	//
				// if the server IP is "localhost", run the test command in a new process
				if (perfConfig.serverIP.Equals("localhost"))
				{
					rcbg_Cmd = test;
	        		rcbg_Arg = param;
	        		try
		        	{
		            	(new Thread(new ThreadStart(runCommandByGlobalVars))).Start();
		        	}
		        	catch{}
				}
	        	//
	        	// run the desired test
	        	// 
	        	output = "running: " + test + " " + param + " " + perfConfig.serverIP + "\n\n";
	        	output += (runCommand(test, param + " " + perfConfig.serverIP));
	        		
	        	// return output
	        	return output;
        	}
        	catch (Exception ex)
        	{
        		return output
        			+ "\n\nerror "
                    + ex.Message + "\n"
                    + ex.InnerException;
        	}
        }
        //-------------------------------------------------------------------------------------------
        //
        
        public void startScaningCards()
        {
        	try
        	{
            	(new Thread(new ThreadStart(getIbCardsList))).Start();
        	}
        	catch{}
        }
        //-------------------------------------------------------------------------------------------
        //
        /// <summary>
        /// get a list of cards using ibstat 
        /// </summary>
        private void getIbCardsList()
        {
			string ibstat = runCommand("ibstat", "");
			if (ibstat.Contains("error")) 
				return;
            // parse the ibstat output
            try
            {
            	cards = new ArrayList();
	            ibstat = Regex.Replace(ibstat, "\r", "");
	            string []lines = Regex.Split(ibstat, "\n");
	            Card tmp = null; 
	            int portNum = 1;
	            bool flagInc = false;
	            for (int i = 0; i < lines.Length ; i++)
	            {
	            	//name
	            	if (lines[i].Contains("CA '"))
	            	{
	            		flagInc = false;
	            		portNum = 1;
	            		tmp = new Card();
	            		tmp.name = Regex.Split(lines[i], " '")[1].TrimEnd('\'');
	            	}
	            	//physPortCount
	            	if (lines[i].Contains("Number of ports"))
	            	{
	            		tmp.physPortCount = Int32.Parse(Regex.Replace(Regex.Split(lines[i], ": ")[1], " ", ""));
	            	}
	            	//nodeGuid
	            	if (lines[i].Contains("Node GUID"))
	            	{
	            		tmp.nodeGuid = Regex.Split(lines[i], ": ")[1];
	            	} 
	            	// port_1_Active
	            	if (lines[i].Contains("State:") && portNum == 1)
	            	{
	            		flagInc = true;
	            		if (lines[i].Contains("Active"))
	            		{
	            			tmp.port_1_Active = true;
	            		}
	            		if (tmp.physPortCount == 1)
	            		{
	            			cards.Add(tmp);
	            		}
	            	} 
	            	// port_2_Active 
	            	if (lines[i].Contains("State:") && portNum == 2)
	            	{
	            		if (lines[i].Contains("Active"))
	            		{
	            			tmp.port_2_Active = true;
	            		}
	            		if (tmp.physPortCount == 2)
	            		{
	            			cards.Add(tmp);
	            		}
	            	} 
	            	if (flagInc)
	            	{
	            		portNum = 2;
	            	}
	            }
	            
	            // select the card with active port
	            if (cards != null)
	            {
		            for (int i = 0; i < cards.Count ; i++)
		            {
		            	if (((Card)cards[i]).port_1_Active)
		            	{
		            		LogicAbstract.perfConfig = new PerformanceConf();
							LogicAbstract.perfConfig.serverIP = "localhost";
							LogicAbstract.perfConfig.clinetIbDevGuid = ((Card)cards[i]).nodeGuid;
							LogicAbstract.perfConfig.clinetIbDevName = ((Card)cards[i]).name;
							LogicAbstract.perfConfig.clinetIbPortNum = "1";
							LogicAbstract.perfConfig.runPerfTests = true;
							break;
		            	}
		            	else
		            	if (((Card)cards[i]).port_2_Active)
		            	{
		            		LogicAbstract.perfConfig = new PerformanceConf();
							LogicAbstract.perfConfig.serverIP = "localhost";
							LogicAbstract.perfConfig.clinetIbDevGuid = ((Card)cards[i]).nodeGuid;
							LogicAbstract.perfConfig.clinetIbDevName = ((Card)cards[i]).name;
							LogicAbstract.perfConfig.clinetIbPortNum = "2";
							LogicAbstract.perfConfig.runPerfTests = true;
							break;
		            	}
		            }
	            }
            }
            catch(Exception ex)
            {
            	cards = null;
            	//MessageBox.Show(ex.InnerException.Message + "\n" + ex.Message);
            }
        }
        //-------------------------------------------------------------------------------------------
        //
        
	    private void sortCommandsArrayList(ref ArrayList list)
	    {
	    	try
	    	{
	        	SortedDictionary<string, Command> sortedDic = new SortedDictionary<string, Command>();
	        	for (int i = 0; i < list.Count; i++)
	        	{
        			Command item = (Command)list[i];
    				sortedDic.Add(item.getName(), item);
	        	}
	        	// creat sorted list
	        	ArrayList sortedlist = new ArrayList();
	        	foreach (KeyValuePair<string, Command> kvp in sortedDic)
	        	{
	        		sortedlist.Add(kvp.Value);
	        	}
	        	// update the list
	        	list = sortedlist;
	    	}
	    	catch
	    	{
	    	}
	    }
        //-------------------------------------------------------------------------------------------
	    //
	    
	   	private void runCommandByGlobalVars()
	   	{
        	runCommand(rcbg_Cmd, rcbg_Arg);
        	rcbg_Cmd = "";
        	rcbg_Arg = "";
	   	}
	   	//-------------------------------------------------------------------------------------------
	    //
    }
}

